%{
    #include "compile.h"
    #include "y.tab.h"
    string tmp;
    char debugstr[100];
    void debugTheLex(void);
    int yycolumn = 1;
    extern YYLTYPE yylloc;
    #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno-1; \
            yylloc.first_column = yycolumn; yylloc.last_column = yycolumn+yyleng-1; \
            yycolumn += yyleng;
    vector<string> lex_error;
    void add_lex_error(string describe, string text, int start, int end);
    void lex_error_print(void);
%}

%option yylineno

%x BBB
%x BB
%x SCH
%x MCH

line \n.*
letter [a-zA-Z]
digit [0-9]
digits {digit}({digit})*
optional_fraction "."{digits}|""
optional_exponent (E(([+-]|""){digits}))|""
/* 数字的识别 */
num {digits}{optional_fraction}{optional_exponent}
/* id 的识别 */
id {letter}({letter}|{digit})*
/* 注释的识别 */
/* annotation_block (\(\*([^)]|[^*]\)|\n)*\*\))|("{"([^"}"])*"}")
annotation_block_e1 (\(\*([^)]|[^*]\)|\n)*)
annotation_block_e2 ("{"([^"}"])*) */
annotation_line ("//"(.)*\n)
blank_chars [ \f\r\t\v]+
%%

{line} {
    yycolumn=1;
    yyless(1); //yyleng是当前匹配的单词的长度,yyless(n)表示退回yyleng-n个字符，只保留n个字符
}
{blank_chars} {}
"(*" {
    #ifdef LEXDEBUG
        printf("annotation_block\n");
    #endif
        BEGIN BBB;
    #ifdef LEXWORK
    #endif
 }
 <BBB>"*)" {
    #ifdef LEXDEBUG
    #endif
        BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
 <BBB>. {
    #ifdef LEXDEBUG
    #endif

    #ifdef LEXWORK
    #endif
}
<BBB>\n {
    #ifdef LEXDEBUG
    #endif

    #ifdef LEXWORK
    #endif
}
<BBB><<EOF>> {
    #ifdef LEXDEBUG
        printf("miss the *)");
    #endif
        BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
"{" {
    #ifdef LEXDEBUG
        printf("annotation_block\n");
        printf("BB\n");
    #endif
        BEGIN BB;
    #ifdef LEXWORK
    #endif
}
<BB>\n {
    #ifdef LEXDEBUG
    #endif

    #ifdef LEXWORK
    #endif
}
<BB>"}" {
    #ifdef LEXDEBUG
    #endif
        BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
<BB>. {
    #ifdef LEXDEBUG
    #endif

    #ifdef LEXWORK
    #endif
}
<BB><<EOF>> {
    #ifdef LEXDEBUG
        printf("miss the }");
    #endif
        BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
"array" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "ARRAY", string(yytext));
        return ARRAY;
    #endif 
}
"begin" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "BEGINN", string(yytext));
        return BEGINN;
    #endif 
}
"case" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "CASE", string(yytext));
        return CASE;
    #endif  
}
"const" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "CONST", string(yytext));
        return CONST;
    #endif  
}
"do" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DO", string(yytext));
        return DO;
    #endif  
}
"downto" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DOWNTO", string(yytext));
        return DOWNTO;
    #endif  
}
"else" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "ELSE", string(yytext));
        return ELSE;
    #endif 
}
"end" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "END", string(yytext));
        return END;
    #endif 
}
"for" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "FOR", string(yytext));
        return FOR;
    #endif
}
"function" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "FUNCTION", string(yytext));
        return FUNCTION;
    #endif
}
"if" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "IF", string(yytext));
        return IF;
    #endif
}
"not" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "NOT", string(yytext));
        return NOT;
    #endif
}
"of" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "OF", string(yytext));
        return OF;
    #endif
}
"procedure" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "PROCEDURE", string(yytext));
        return PROCEDURE;
    #endif
}
"program" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "PROGRAM", string(yytext));
        return PROGRAM;
    #endif
}
"record" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "RECORD", string(yytext));
        return RECORD;
    #endif
}
"repeat" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "REPEAT", string(yytext));
        return REPEAT;
    #endif
}
"then" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "THEN", string(yytext));
        return THEN;
    #endif
}
"to" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "TO", string(yytext));
        return TO;
    #endif
}
"type" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "TYPE", string(yytext));
        return TYPE;
    #endif
}
"until" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "UNTIL", string(yytext));
        return UNTIL;
    #endif
}
"var" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "VAR", string(yytext));
        return VAR;
    #endif
}
"while" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "WHILE", string(yytext));
        return WHILE;
    #endif
}
"boolean" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "BOOLEAN", string(yytext));
        return BOOLEAN;
    #endif
}
"integer" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "INTEGER", string(yytext));
        return INTEGER;
    #endif
}
"real" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "REAL", string(yytext));
        return REAL;
    #endif
}
"char" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "CHAR", string(yytext));
        return CHAR;
    #endif
}
"string" {
	#ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "STRING", string(yytext));
        return STRING;
    #endif
}
"," {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "COMMA", string(yytext));
        return COMMA;
    #endif
}
";" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "SEMICOLON", string(yytext));
        return SEMICOLON;
    #endif
}
"." {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DOT", string(yytext));
        return DOT;
    #endif
}
".." {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DDOT", string(yytext));
        return DDOT;
    #endif
}
"(" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "LPAR", string(yytext));
        return LPAR;
    #endif
}
")" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "RPAR", string(yytext));
        return RPAR;
    #endif
}
"[" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "LBAR", string(yytext));
        return LBAR;
    #endif
}
"]" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "RBAR", string(yytext));
        return RBAR;
    #endif
}
{num} {
    #ifdef LEXDEBUG
        printf("num ");
        printf(yytext);
        printf("\n");
    #endif

    #ifdef LEXWORK
        string temp = string(yytext);
        string::size_type position1 = temp.find(".");
        string::size_type position2 = temp.find("e");
        if(position1 == temp.npos && position2 == temp.npos){
            yylval = new parse(yylineno, "INT", string(yytext));
        }
        else{
            yylval = new parse(yylineno, "FLOAT", string(yytext));
        }
        return NUM;
    #endif
}
"=" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "EQUAL", "EQUAL");
        return EQUAL;
    #endif
}
"<>" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "NEQUAL", "NEQUAL");
        return NEQUAL;
    #endif
}
"<" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "LESS", "LESS");
        return LESS;
    #endif
}
"<=" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "LE", "LE");
        return LE;
    #endif
}
">" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "GREATER", "GREATER");
        return GREATER;
    #endif
}
">=" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "GE", "GE");
        return GE;
    #endif
}
"+" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "ADD", "ADD");
        return ADD;
    #endif
}
"-" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "SUB", "SUB");
        return SUB;
    #endif
}
"or" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "OR", "OR");
        return OR;
    #endif
}
"*" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "MUL", "MUL");
        return MUL;
    #endif
}
"/" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DIVISION", "DIVISION");
        return DIVISION;
    #endif
}
"div" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "DIV", "DIV");
        return DIV;
    #endif
}
"mod" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "MOD", "MOD");
        return MOD;
    #endif
}
"AND" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "AND", "AND");
        return AND;
    #endif
}
":=" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "ASSIGNOP", string(yytext));
        return ASSIGNOP;
    #endif
}
":" {
    #ifdef LEXDEBUG
        debugTheLex();
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "COLON", string(yytext));
        return COLON;
    #endif
}
{id} {
    #ifdef LEXDEBUG
        printf("id ");
        printf(yytext);
        printf("\n");
    #endif

    #ifdef LEXWORK
        yylval = new parse(yylineno, "ID", string(yytext));
        return ID;
    #endif
}
{annotation_line} {
    #ifdef LEXDEBUG
        //注意行号
       printf("annotation_line\n"); 
    #endif

    #ifdef LEXWORK
    
    #endif
}
\' {
    #ifdef LEXDEBUG
        printf("begin SCH\n");
    #endif
    BEGIN SCH;
    tmp = "";
    #ifdef LEXWORK
    #endif

}
<SCH>("'") {
    #ifdef LEXDEBUG
        printf("end SCH\n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
		if(tmp.size()==0)
            printf("error the size is 0");
		else
		{
			yylval = new parse(yylineno, "SSCH", tmp);
			//cout<<tmp<<endl;
			return SSCH;
		}
    #endif
}
<SCH>. {
    tmp+=yytext[0];
}

<SCH>\n {
    #ifdef LEXDEBUG
        printf("error miss ' \n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
<SCH><<EOF>> {
    #ifdef LEXDEBUG
        printf("error miss ' at end of file\n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
\" {
    #ifdef LEXDEBUG
        printf("beging MCH\n");
    #endif

    BEGIN MCH;
    tmp = "";
    #ifdef LEXWORK
    #endif

}
<MCH>\" {
    #ifdef LEXDEBUG
        printf("end MCH\n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
		yylval = new parse(yylineno, "MMCH", tmp);
		//cout<<tmp<<endl;
		return MMCH;
    #endif
}
<MCH>. {
    tmp+=yytext[0];
}
<MCH>\n {
    #ifdef LEXDEBUG
        printf("error miss \" \n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}
<MCH><<EOF>> {
    #ifdef LEXDEBUG
        printf("error miss \" at end of file\n");
    #endif
    BEGIN INITIAL;
    #ifdef LEXWORK
    #endif
}

. {
    add_lex_error("Invalid character!", string(yytext), yycolumn-yyleng, yycolumn-1);
}


%%

/* int main(void)
{
    yylex();
}

int yywrap()
{
	return 1;
} */

void debugTheLex(void)
{
    strcpy(debugstr,yytext);
    printf("%s\n", debugstr);
}

void add_lex_error(string describe, string text, int start, int end)
{
    string error = describe;
    error = error + " at " + to_string(yylineno);
    error = error + " start at " + to_string(start);
    error = error + " end at " + to_string(end);
    error = error + " where \"" + text + "\"";
    lex_error.push_back(error);
}

void lex_error_print(void)
{
    for(auto it = lex_error.begin(); it != lex_error.end(); it++){
        cout << (*it) << endl;
    }
}
